package com.example.apidocserver.infrastructure.util.document;

import com.alibaba.druid.util.StringUtils;
import com.example.apidocserver.domain.document.entity.ApiInfo;
import com.example.apidocserver.domain.document.entity.ApiParam;
import com.example.apidocserver.domain.document.entity.ApiParamField;
import com.example.apidocserver.domain.document.entity.ApiParamHis;
import com.example.apidocserver.domain.system.entity.AllEnum;
import com.example.apidocserver.infrastructure.constants.SystemConstants;
import com.example.apidocserver.infrastructure.util.word.WordTableUtil;
import com.example.apidocserver.interfaces.vo.ApiParamDescVo;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.example.apidocserver.infrastructure.util.word.WordParagraphUtil.*;
import static com.example.apidocserver.infrastructure.util.word.WordTableUtil.setCellText;
import static com.example.apidocserver.infrastructure.util.word.WordTableUtil.setTitle;

/**
 * 实体对象转word工具
 *
 * @author xyqlg
 */
public class EntityToWord {
    /**
     * id对应字段类型
     */
    public final static Map<Integer, String> ID_AND_NAME_TYPE_MAP = new HashMap<>(8);
    /**
     * 字段名称
     */
    public final static String[] FIELD_TITLE_STR = {"字段名称", "字段类型", "是否必须", "字段说明"};


    public static int startTitleNo(Integer startTitleNo) {
        return Objects.isNull(startTitleNo) || startTitleNo < 1 ? 2 : startTitleNo;
    }

    public static boolean typeIsNull() {
        return ID_AND_NAME_TYPE_MAP.isEmpty();
    }

    public static void setTypeMap(AllEnum allEnum) {
        if (Objects.isNull(allEnum) || CollectionUtils.isEmpty(allEnum.getChildren())) {
            return;
        }
        for (AllEnum child : allEnum.getChildren()) {
            ID_AND_NAME_TYPE_MAP.put(child.getEnumValue(), child.getEnumName());
        }
    }

    /**
     * 设置接口信息
     *
     * @param document 文档信息
     * @param apiInfo  接口信息
     */
    public static void setApiInfo(XWPFDocument document, ApiInfo apiInfo) {
        getTitle2Run(document, apiInfo.getApiName(), 2);
        getTitle2Run(document, "1.接口信息", 3);
        addParagraphs(document, apiInfo.getApiDesc());
        getTitle2Run(document, "1.1.接口信息", 4);
        getParagraph(document, apiInfo.getApiType() + "   " + apiInfo.getApiUri());
        getTitle2Run(document, "1.2.服务信息", 4);
        addParagraphs(document, apiInfo.getApiHeader());
    }

    /**
     * 设置参数说明
     *
     * @param document       文档信息
     * @param apiParamDescVo 参数说明
     */
    public static void setParamDesc(XWPFDocument document, ApiParamDescVo apiParamDescVo) {
        getTitle2Run(document, "2.参数&字段说明", 3);
        getTitle2Run(document, "2.1.入参参数", 4);
        setNotBodyParamDesc(document, "入参头参数说明", apiParamDescVo.getInputHeader());
        setNotBodyParamDesc(document, "入参路径参数说明", apiParamDescVo.getInputPath());
        setNotBodyParamDesc(document, "入参查询参数说明", apiParamDescVo.getInputQuery());
        setBodyParamDesc(document, "入参体参数说明", apiParamDescVo.getInputBody());

        getTitle2Run(document, "2.2.返回参数", 4);
        setNotBodyParamDesc(document, "返回头参数说明", apiParamDescVo.getOutputHeader());
        setBodyParamDesc(document, "返回体参数说明", apiParamDescVo.getOutputBody());
    }

    /**
     * 设置参数示例
     *
     * @param document        文档信息
     * @param currentParamHis 参数示例
     */
    public static void setParamHis(XWPFDocument document, ApiParamHis currentParamHis) {
        getTitle2Run(document, "3.参数示例", 3);
        getTitle2Run(document, "3.1.入参参数示例", 4);
        setInputHis(document, currentParamHis);

        getTitle2Run(document, "3.2.返回参数示例", 4);
        setOutputHis(document, currentParamHis);
    }

    private static void setInputHis(XWPFDocument document, ApiParamHis currentParamHis) {
        setHisStr(document, "入参头参数示例", currentParamHis.getParamInputHeaderStr());
        setHisStr(document, "入参路径参数示例", currentParamHis.getParamInputPathStr());
        setHisStr(document, "入参查询参数示例", currentParamHis.getParamInputQueryStr());
        setHisStr(document, "入参体参数示例", currentParamHis.getParamInputBodyStr());
    }

    private static void setOutputHis(XWPFDocument document, ApiParamHis currentParamHis) {
        setHisStr(document, "返回头参数示例", currentParamHis.getParamOutputHeaderStr());
        setHisStr(document, "返回体参数示例", currentParamHis.getParamOutputBodyStr());
    }

    private static void setHisStr(XWPFDocument document, String title, String paramOutputBodyStr) {
        if (StringUtils.isEmpty(paramOutputBodyStr)) {
            return;
        }
        XWPFParagraph title2Run = getTitle2Run(document, title, 5);
        title2Run.setSpacingBefore(60);
        addParagraphs(document, paramOutputBodyStr);
    }

    private static void setBodyParamDesc(XWPFDocument document, String title, List<ApiParam> inputBody) {
        if (CollectionUtils.isEmpty(inputBody)) {
            return;
        }
        XWPFParagraph title2Run = getTitle2Run(document, title, 5);
        title2Run.setSpacingBefore(80);
        for (ApiParam apiParam : inputBody) {
            if (CollectionUtils.isEmpty(apiParam.getFields())) {
                continue;
            }
            XWPFParagraph paragraph = getParagraph(document, apiParam.getTitle());
            paragraph.setAlignment(ParagraphAlignment.CENTER);
            paragraph.setSpacingBefore(30);
            for (XWPFRun run : paragraph.getRuns()) {
                run.setBold(true);
            }
            setFieldTable(document, apiParam);
        }
    }

    private static void setNotBodyParamDesc(XWPFDocument document, String title, ApiParam param) {
        if (Objects.isNull(param) || CollectionUtils.isEmpty(param.getFields())) {
            return;
        }
        XWPFParagraph title2Run = getTitle2Run(document, title, 5);
        title2Run.setSpacingBefore(60);
        setFieldTable(document, param);
    }

    private static void setFieldTable(XWPFDocument document, ApiParam param) {
        addParagraphs(document, param.getParamDesc());
        XWPFTable table = document.createTable(param.getFields().size() + 1, 4);
        setTableTitle(table);
        for (int i = 0; i < param.getFields().size(); i++) {
            setFieldDesc(table, param.getFields().get(i), i + 1);
        }
    }

    private static void setFieldDesc(XWPFTable table, ApiParamField field, int rowNo) {
        WordTableUtil.setTableColumnWidth(table, rowNo);
        XWPFTableRow row = table.getRow(rowNo);

        boolean boldFlag = SystemConstants.STR_YES.equals(field.getFieldMust());
        setCellText(row, 0, field.getFieldName(), boldFlag);
        String fieldTypeStr = ID_AND_NAME_TYPE_MAP.get(field.getFieldTypeId());
        fieldTypeStr = StringUtils.isEmpty(fieldTypeStr) ? String.valueOf(field.getFieldTypeId()) : fieldTypeStr;
        setCellText(row, 1, fieldTypeStr, boldFlag);
        setCellText(row, 2, field.getFieldMust(), boldFlag);
        setCellText(row, 3, field.getFieldDesc(), boldFlag);
    }

    private static void setTableTitle(XWPFTable table) {
        WordTableUtil.setTableColumnWidth(table, 0);
        setTitle(table, 0, FIELD_TITLE_STR);
    }
}
